"""
This module provides access to application settings stored in the file ~/.pybookshelf/settings.ini
"""
import ConfigParser
import os
import re
import gtk.gdk
from . import exceptions
from . import log
from . import path
from gtk.gdk import color_parse

parser = None

# default values
__defaults = {
    'ui/cover_max_width_html': "300",
    'ui/open_new_tab_after_current_one': "False",
    'ui/ellipsis_in_center': "False",
    'ui/open_report_after_update': "False",
    'ui/display_rating_on_search_results': "False",
    'ui/rename_exported_books': "False",
    'ui/report_viewer': "",
    'style/normal_font': "Serif 12",
    'style/headers_font': "Sans 22",
    'style/background_color': "#ffffffffffff",
    'style/hyperlinks_color': "#00000000ffff",
    'style/hover_links_color': "#0000ffff0000",
    'style/normal_text_color': "#000000000000",
    'ui/last_tab': "0",
    'ui/mainw_maximized': "False",
    'ui/ellipsis_in_center': "False",
    'ui/open_new_tab_after_current_one': "False",
    'ui/mainw_maximized': "False",
    'paths/multiple_files_save_target_dir': path.home,
    'ui/rename_exported_books': "False",
    'ui/report_viewer': "",
    'ui/open_report_after_update': "False",
    'manage_bookmarks_splitter_pos': "100",
    'ui/cdirs_width': "400",
    'ui/cdirs_height': "300",
    'collection/dirs': "[]",
    'ui/display_rating_on_search_results': "False",
    'paths/file_save_target_dir': path.home,
    'ui/detailed_msgdialog_width': "400",
    'ui/detailed_msgdialog_height': "300",
    'collection/dirs': "[]",
    'pdf/external_viewer': "evince",
    'txt/external_viewer': "",
    'fb2/ui/edit_book_handle_pos': "100",
    'fb2/authors_presets': "[]",
    'fb2/external_viewer': "FBReader",
    'fb2/use_internal_viewer': "False",
    
    'ui/main_win_width': "640",
    'ui/main_win_height': "480",
    'ui/main_win_x': "0",
    'ui/main_win_y': "0",
    
    'ui/manage_bookmarks_win_width': "300",
    'ui/manage_bookmarks_win_height': "500",
    'ui/manage_bookmarks_win_x': "0",
    'ui/manage_bookmarks_win_y': "0",
    
    'ui/edit_metadata_win_width': "400",
    'ui/edit_metadata_win_height': "300",
    'ui/edit_metadata_win_x': "0",
    'ui/edit_metadata_win_y': "0",
    
    'ui/edit_metadata_item_win_width': "300",
    'ui/edit_metadata_item_win_height': "300",
    'ui/edit_metadata_item_win_x': "0",
    'ui/edit_metadata_item_win_y': "0",
    
    'fb2/edit_book_win_width': "400",
    'fb2/edit_book_win_height': "300",
    'fb2/edit_book_win_x': "100",
    'fb2/edit_book_win_y': "100",
    
    'fb2/edit_authors_presets_win_width': "400",
    'fb2/edit_authors_presets_win_height': "300",
    'fb2/edit_authors_presets_win_x': "100",
    'fb2/edit_authors_presets_win_y': "100",
    }

class PbsConfigParser(ConfigParser.SafeConfigParser):
    def __init__(self, path):
        ConfigParser.SafeConfigParser.__init__(self)
        self.path = path

    def add_section(self, section_name="", plugin=None):

        section_name_str = section_name
        if plugin:
            section_name_str = "plugin/%s" % plugin

        log.debug("Adding section [%s]" % section_name_str)

        try:
            ConfigParser.SafeConfigParser.add_section(self, section_name_str)
        except ConfigParser.DuplicateSectionError, e:
            log.error(e)

    def get_section_key(self, key, plugin=None):
        plugin_str = plugin
        section_key = None

        if plugin:
            if plugin.endswith(".py"):
                plugin_str = plugin[:-3]

        if plugin_str:
            section_name_str = "plugin/%s" % plugin
            if section_name_str not in self.sections():
                self.add_section(plugin=plugin_str)

            section_key = ("plugin/%s" % plugin_str, key)
        else:
            split_str = key.split("/", 1)
            if len(split_str) > 1:
                section_key = (split_str[0], split_str[1])
            else:
                section_key = ("general", split_str[0])

        return section_key

    def get_section_keyv(self, key, plugin, value):
        return self.get_section_key(key, plugin) + (value,)
        
def initialize(path):
    """
    Initialize module. Initialize config parser and read settings from the settings file.
    
    @param path: path to the file with settings
    """
    global parser

    if not parser is None:
        raise exceptions.SettingsError("Settings module already initialized!")

    parser = PbsConfigParser(path)
    sections = ["general", "ui", "style", "collection", "paths"]
    
    if os.path.exists(path) and not os.path.isfile(path):
        raise exceptions.SettingsError("Invalid path to settings file, must be a regular file!")

    if os.path.exists(path):
        try:
            parser.read(path)
        except ConfigParser.MissingSectionHeaderError:
            # append missing sections
            map(parser.add_section, sections)

            from config_convert import ConvertIniToConf
            converter = ConvertIniToConf(parser, path)

    map(parser.add_section, sections)

def get_value(key, default, plugin=None):
    global parser

    if parser is None:
        raise exceptions.SettingsError("Settings module is not initialized!")
    value = None
    try:
        value = parser.get(*parser.get_section_key(key, plugin))
    except ConfigParser.NoOptionError:
        pass

    if value is None:
        # try to get dafault value from the list of default values
        d_key = key
        if plugin is not None:
            d_key = plugin + "/" + d_key
        if d_key in __defaults:
            value = __defaults[d_key]
        else:
            log.error("Unable to find default setting value for the key `%s'" % d_key)
            value = default

    return value

def get_boolean(key, plugin=None):
    """
        Gets a boolean value from the settings
    """
    default = False
    value = get_value(key, default=str(default), plugin=plugin)
    
    if "True" == value or "true" == value:
        value = True
    elif "False" == value or "false" == value:
        value = False
    else:
        value = default

    return value

def get_int(key, plugin=None):
    """
        Get an integer value from the settings
    """
    default = 0
    value = get_value(key, default=str(default), plugin=plugin)

    try:
        value = int(value)
    except ValueError:
        value = default

    return value

def get_str(key, plugin=None):
    """
        Get a string value from the settings
    """
    default = ""
    value = get_value(key, default=default, plugin=plugin)

    if value is None:
        value = default

    return value

def get_list(key, plugin=None):
    """
        Get a list value from the settings
    """
    default = []
        
    value = get_value(key, default=str(default), plugin=plugin)

    try:
        # FIXME rewrite in more safe way
        value = eval(value)
    except SyntaxError:
        value = default

    return value

def get_dict(key, plugin=None):
    """
    Get a dict value from the settings
    """
    default = dict()
        
    value = get_value(key, default=str(default), plugin=plugin)
    
    try:
        # FIXME rewrite in more safe way
        value = eval(value)
    except SyntaxError:
        value = default
        
    return value

def get_gdk_color(key, plugin=None):
    """
    Get gtk.gdk.Color value
    """
    default = gtk.gdk.color_parse("#FFF") # white color is default
    
    value = get_value(key, default=default.to_string(), plugin=plugin)
    
    try:
        value = gtk.gdk.color_parse(value)
    except ValueError, e:
        log.debug("settings.get_gdk_color() failed: %s on value `%s'" % (e, value))
        value = default
        
    return value

def set_value(key, value, plugin=None):
    global parser
    
    if None == parser:
        raise exceptions.SettingsError("Settings module is not initialized!")

    parser.set(*parser.get_section_keyv(key, plugin, value))
    
def set_boolean(key, value, plugin=None):
    value_str = str(value)
    
    value = False
    if value_str == "true" or value_str == "True": 
        value = True
        
    if value_str == "false" or value_str == "False": 
        value = False
        
    set_value(key, str(value), plugin)
    
def set_int(key, value, plugin=None):
    set_value(key, str(value), plugin)


def set_str(key, value, plugin=None):
    value_str = str(value)
    value_str = re.sub(r'%[^rdf%]?', r'%%', value_str)
    set_value(key, value_str, plugin)

def set_list(key, value, plugin=None):
    set_value(key, str(value), plugin)
    
def set_dict(key, value, plugin=None):
    set_value(key, str(value), plugin)

def set_gdk_color(key, value, plugin=None):
    set_value(key, value.to_string(), plugin)
    
def set(key, value):
    """
        Sets a value
    """
    func = lambda k,v: 1

    if isinstance(value, bool):
        func = set_boolean
    elif isinstance(value, int):
        func = set_int
    elif isinstance(value, str):
        func = set_str

    func(key, value)

def save():
    f = open(parser.path, "w")
    parser.write(f)
    f.close()
    
def remember_window_geometry(window, settings_prefix, plugin=None):
    width, height = window.get_size()
    set_int("ui/%s_win_width" % settings_prefix, width, plugin=plugin) 
    set_int("ui/%s_win_height" % settings_prefix, height, plugin=plugin) 
    x, y = window.get_position()
    set_int("ui/%s_win_x" % settings_prefix, x, plugin=plugin) 
    set_int("ui/%s_win_y" % settings_prefix, y, plugin=plugin) 
    
def restore_window_geometry(window, settings_prefix, plugin=None):
    width = get_int("ui/%s_win_width" % settings_prefix, plugin=plugin)
    height = get_int("ui/%s_win_height" % settings_prefix, plugin=plugin)
    x = get_int("ui/%s_win_x" % settings_prefix, plugin=plugin)
    y = get_int("ui/%s_win_y" % settings_prefix, plugin=plugin)
    
    window.resize(width, height)
    window.move(x, y)
